package com.ease.integration.snmp;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import org.snmp4j.CommunityTarget;
import org.snmp4j.PDU;
import org.snmp4j.Snmp;
import org.snmp4j.event.ResponseEvent;
import org.snmp4j.smi.Integer32;
import org.snmp4j.smi.Null;
import org.snmp4j.smi.OID;
import org.snmp4j.smi.VariableBinding;

public class SnmpTemplate {

	private Snmp snmp = null;

	private CommunityTarget target;

	public static String GET = "get";

	public static String GETNET = "getnext";

	public static String WALK = "walk";

	private SnmpClient snmpClient = null;

	private boolean connect() throws RuntimeException {
		return snmpClient.connect();
	}

	private boolean disconnect() {
		return snmpClient.disconnect();
	}

	protected <T> T execute(SnmpExecutionCallback<T> snmpExecutionCallback) throws RuntimeException {
		try {
			this.connect();

			return snmpExecutionCallback.execute();
		} catch (Exception e) {
			// TODO
			e.printStackTrace();
		} finally {
			this.disconnect();
		}
		return (T) null;
	}

	public String get(final String oid) throws RuntimeException {
		return this.execute(new SnmpExecutionCallback<String>() {

			public String execute() {
				return snmpClient.get(oid);
			}

		});
	}

	public String doGet(String oid) throws Exception {
		String result = "";
		PDU request = new PDU();
		request.setType(PDU.GET);
		request.add(new VariableBinding(new OID(oid)));
		ResponseEvent responseEvent = snmp.send(request, target);
		PDU response = responseEvent.getResponse();
		if (response != null && response.getErrorIndex() == PDU.noError && response.getErrorStatus() == PDU.noError) {
			VariableBinding vb = response.get(0);
			System.out.println(vb.toString());
			result = vb.toString().split("=")[1].trim();
			if ("noSuchObject".equals(result))
				result = "";
		} else if (response != null) {
			System.out.println("get error:" + response.getErrorStatusText());
		} else {
			System.out.println("There are some errors!");
		}

		return result;
	}

	public String doGetNext(String oid) throws Exception {
		String result = "";
		PDU request = new PDU();
		request.setType(PDU.GETNEXT);
		request.add(new VariableBinding(new OID(oid)));
		ResponseEvent responseEvent = snmp.send(request, target);
		PDU response = responseEvent.getResponse();
		if (response != null && response.getErrorIndex() == PDU.noError && response.getErrorStatus() == PDU.noError) {
			VariableBinding vb = response.get(0);
			System.out.println(vb.toString());
			result = vb.toString().split("=")[1].trim();
			if ("noSuchObject".equals(result))
				result = "";
		} else if (response != null) {
			System.out.println("get error:" + response.getErrorStatusText());
		} else {
			System.out.println("There are some errors!");
		}

		return result;
	}

	public Map<String, String> doWalk(String root) throws IOException {
		PDU response;
		PDU request = new PDU();
		request.setType(PDU.GETNEXT);
		request.add(new VariableBinding(new OID(root)));
		Map<String, String> resultList = new HashMap<String, String>();
		OID rootOID = request.get(0).getOid();
		do {
			ResponseEvent responseEvent = snmp.send(request, target);
			response = responseEvent.getResponse();
		} while (!processWalk(response, request, rootOID, resultList));
		return resultList;
	}

	/*
	 * public void doWalk(String root, Map resultList) throws IOException { PDU response; PDU request = new PDU();
	 * request.setType(PDU.GETNEXT); request.add(new VariableBinding(new OID(root))); OID rootOID =
	 * request.get(0).getOid(); do { ResponseEvent responseEvent = snmp.send(request, target); response =
	 * responseEvent.getResponse(); } while (!processWalk(response, request, rootOID, resultList)); }
	 */

	public boolean doWalk(String root, Map<String, String> resultList) throws IOException {
		PDU response;
		PDU request = new PDU();
		request.setType(PDU.GETNEXT);
		request.add(new VariableBinding(new OID(root)));
		OID rootOID = request.get(0).getOid();
		do {
			ResponseEvent responseEvent = snmp.send(request, target);
			response = responseEvent.getResponse();
			if (response == null)
				return false;
		} while (!processWalk(response, request, rootOID, resultList));
		return true;
	}

	private boolean processWalk(PDU response, PDU request, OID rootOID, Map<String, String> list) {

		if ((response == null) || (response.getErrorStatus() != 0) || (response.getType() == PDU.REPORT)) {
			return true;
		}
		boolean finished = false;
		OID lastOID = request.get(0).getOid();
		for (int i = 0; (!finished) && (i < response.size()); i++) {
			VariableBinding vb = response.get(i);
			if ((vb.getOid() == null) || (vb.getOid().size() < rootOID.size()) || (rootOID.leftMostCompare(rootOID.size(), vb.getOid()) != 0)) {
				finished = true;
			} else if (Null.isExceptionSyntax(vb.getVariable().getSyntax())) {
				finished = true;
			} else if (vb.getOid().compareTo(lastOID) <= 0) {
				finished = true;
			} else {
				lastOID = vb.getOid();
				list.put(vb.toString().split("=")[0], vb.toString().split("=")[1].trim());
				System.out.println(vb.toString());
			}
		}

		if (response.size() == 0) {
			finished = true;
		}
		if (!finished) {
			VariableBinding next = response.get(response.size() - 1);
			next.setVariable(new Null());
			request.set(0, next);
			request.setRequestID(new Integer32(0));
		}
		return finished;
	}

	public void release() throws IOException {

	}

	/**
	 * @return the snmpClient
	 */
	public SnmpClient getSnmpClient() {
		return snmpClient;
	}

	/**
	 * @param snmpClient
	 *            the snmpClient to set
	 */
	public void setSnmpClient(SnmpClient snmpClient) {
		this.snmpClient = snmpClient;
	}

}
